<template>
  <div>
    <h1>Combat Script Visual</h1>
    <div class="table-container">

      <el-row style="margin-bottom: 10px; display: flex; align-items: center;">

        <el-col :span="4" style="text-align: left;">
          <el-select v-model="targetIp" filterable allow-create default-first-option placeholder="请选择作用平台或者自定义ip"
            style="padding: 10px 20px 10px 0;">
            <template #default>
              <el-option
                v-for="item in targetLocation"
                :key="item"
                :label="item"
                :value="item"
              >
                <span style="float:left">{{ item }}</span>
                <el-button
                  v-if="item !== '开发服'"
                  type="text"
                  @click.stop="removeTargetLocation(item)"
                  style="float:right;color:red;"
                >×</el-button>
              </el-option>
            </template>
          </el-select>
        </el-col>

        <el-col :span="18" style="display: flex; align-items: center;">
          <el-input v-model.number="scriptId" placeholder="请输入需要修改的配置ID" style="padding: 10px 20px 10px 0; margin-left: 20px;"
            @keyup.enter="searchScript" type="number" />
          <el-button type="primary" @click="searchScript" style="width: 120px;">搜索</el-button>
        </el-col>
      </el-row>

      <el-tabs v-model="activeTab" @tab-click="handleTabClick">
        <el-tab-pane :label="CombatSkillTableConfig.name" :name="CombatSkillTableConfig.name">

          <!-- 选中单元格展示区域 -->
          <div class="selected-cell-display">
            <div class="display-header">
              <span>选中单元格: {{ selectedCellLabel }}</span>
              <el-button type="primary" size="small" @click="updateCellToTable">应用修改</el-button>
            </div>
            <div class="display-content">
              <el-input v-if="!isNumericCell" v-model="selectedCellData" size="medium" />
              <el-input-number v-else v-model="selectedCellData" size="medium" :controls="false" style="width: 100%;" />
            </div>
          </div>

          <hot-table ref="combatSkillTableComponent" :settings="combatSkillHotSettings"></hot-table>
        </el-tab-pane>
        <el-tab-pane :label="DmgTableConfig.name" :name="DmgTableConfig.name">

          <!-- 选中单元格展示区域 -->
          <div v-if="selectedCellData !== null" class="selected-cell-display">
            <div class="display-header">
              <span>选中单元格: {{ selectedCellLabel }}</span>
              <el-button type="primary" size="small" @click="updateCellToTable">应用修改</el-button>
            </div>
            <div class="display-content">
              <el-input v-if="!isNumericCell" v-model="selectedCellData" size="medium" />
              <el-input-number v-else v-model="selectedCellData" size="medium" :controls="false" style="width: 100%;" />
            </div>
          </div>

          <hot-table ref="dmgTableComponent" :settings="dmgHotSettings"></hot-table>
        </el-tab-pane>

        <el-tab-pane :label="BuffTableConfig.name" :name="BuffTableConfig.name">

          <!-- 选中单元格展示区域 -->
          <div v-if="selectedCellData !== null" class="selected-cell-display">
            <div class="display-header">
              <span>选中单元格: {{ selectedCellLabel }}</span>
              <el-button type="primary" size="small" @click="updateCellToTable">应用修改</el-button>
            </div>
            <div class="display-content">
              <el-input v-if="!isNumericCell" v-model="selectedCellData" size="medium" />
              <el-input-number v-else v-model="selectedCellData" size="medium" :controls="false" style="width: 100%;" />
            </div>
          </div>

          <hot-table ref="buffTableComponent" :settings="buffHotSettings"></hot-table>
        </el-tab-pane>
      </el-tabs>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, watch, onUnmounted, inject, type Ref } from 'vue'
import { HotTable } from '@handsontable/vue3'
import { registerAllModules } from 'handsontable/registry'
import { registerLanguageDictionary, zhCN } from 'handsontable/i18n'
import Handsontable from 'handsontable'
import 'handsontable/dist/handsontable.full.min.css'
import { ElMessage, ElMessageBox, type TabsPaneContext } from 'element-plus'
import type { Axios } from 'axios'
import { CombatSkillTableConfig, DmgTableConfig, BuffTableConfig } from './TableVisualable'
import { CombatSkillTableData, DmgDataTableData, BuffTableData, convertToTableData, TableDataApiConfig, getAllDataCfg, getOneDataCfg, updateOneDataCfg, delOneDataCfg } from './TableVisualableConf'
import { onBeforeRouteLeave } from 'vue-router'

//  ---------------------------------------------- var define ----------------------------------------------
// 注册所有Handsontable模块
registerAllModules()
// 注册中文语言包
registerLanguageDictionary(zhCN)

// 注入全局axios实例
const http = inject<Axios>('http')

// 当前激活的页签
const activeTab = ref(CombatSkillTableConfig.name)

// 脚本名称
const scriptId = ref()

const combatSkillTableData = ref<CombatSkillTableData[]>([])
const dmgTableData = ref<DmgDataTableData[]>([])
const buffTableData = ref<BuffTableData[]>([])

interface HotTableMethods {
  hotInstance: Handsontable
}

const targetIp = ref('开发服')
const targetLocation = ref<string[]>([
  '开发服'
])

// 保存targetIp和targetLocation到localStorage
const saveTargetState = () => {
  localStorage.setItem('table_visualable_target_ip', targetIp.value)
  localStorage.setItem('table_visualable_target_location', JSON.stringify(targetLocation.value))
}

// 从localStorage加载targetIp和targetLocation
const loadTargetState = () => {
  const savedIp = localStorage.getItem('table_visualable_target_ip')
  if (savedIp) {
    targetIp.value = savedIp
  }

  const savedLocation = localStorage.getItem('table_visualable_target_location')
  if (savedLocation) {
    try {
      const locations = JSON.parse(savedLocation)
      console.log('savedLocation', locations)
      if (Array.isArray(locations)) {
        targetLocation.value = locations
      }
    } catch (error) {
      console.error('Error parsing saved target locations:', error)
    }
  }
}

// 组件引用
const combatSkillTableComponent = ref<HotTableMethods | null>(null)
const dmgTableComponent = ref<HotTableMethods | null>(null)

// 表格高度
const tableHeight = ref(500)

// 选中单元格相关
const selectedCellData = ref<any>(null)
const selectedCellRow = ref<number | null>(null)
const selectedCellCol = ref<number | null>(null)
const selectedCellProp = ref<string | null>(null)
const selectedCellLabel = ref<string>('')
const isNumericCell = ref<boolean>(false)


// 按钮渲染器
const buttonRenderer = (instance: Handsontable, td: HTMLTableCellElement, row: number, col: number, prop: string | number, value: any, cellProperties: any) => {
  // 清空单元格内容
  td.innerHTML = '';

  // 创建按钮容器
  const buttonsContainer = document.createElement('div');
  buttonsContainer.style.display = 'flex';
  buttonsContainer.style.gap = '4px';

  // 创建提交按钮
  const submitBtn = document.createElement('button');
  submitBtn.innerHTML = '提交';
  submitBtn.className = 'el-button el-button--primary el-button--small';
  submitBtn.onclick = (e) => {
    e.stopPropagation();
    handleSubmit(row);
  };

  // 创建删除按钮
  const deleteBtn = document.createElement('button');
  deleteBtn.innerHTML = '删除';
  deleteBtn.className = 'el-button el-button--danger el-button--small';
  deleteBtn.onclick = (e) => {
    e.stopPropagation();
    handleDelete(row);
  };

  // 将按钮添加到容器
  buttonsContainer.appendChild(submitBtn);
  buttonsContainer.appendChild(deleteBtn);
  td.appendChild(buttonsContainer);

  // 防止进一步处理
  return td;
};

const HotSettingsTemplate = {
  data: [],                             // 表格数据源，初始为空数组
  dataSchema: [],                // 表格数据结构
  minSpareRows: 0,                                              // 最小剩余行数，0表示不自动添加空白行
  width: '100%',                                                // 表格宽度，占满容器
  height: tableHeight.value,                                    // 表格高度，动态计算
  stretchH: 'none',                                             // 列宽拉伸模式，none表示不自动拉伸
  fixedColumnsStart: 3,                                         // 左侧固定的列数，前两列将始终可见
  rowHeights: 35,
  minRowHeight: 25,
  maxRowHeight: 100,
  colHeaders: [],           // 列标题文本数组
  columns: [],
  contextMenu: false,                                           // 禁用右键上下文菜单
  filters: false,                                               // 禁用过滤功能
  dropdownMenu: false,                                          // 禁用下拉菜单
  language: 'zh-CN',                                            // 设置语言为中文
  rowHeaders: true,                                             // 显示行标题（行号）
  manualColumnResize: true,                                     // 允许手动调整列宽
  manualRowResize: true,                                        // 允许手动调整行高
  columnSorting: false,                                         // 禁用列排序功能
  wordWrap: false,                                              // 禁用文字自动换行
  autoColumnSize: false,                                        // 禁用自动调整列宽
  licenseKey: 'non-commercial-and-evaluation',                  // Handsontable许可证密钥
}

// 表格配置
const combatSkillHotSettings = ref({
  ...HotSettingsTemplate,
  data: combatSkillTableData.value,                             // 表格数据源，初始为空数组
  dataSchema: CombatSkillTableConfig.dataSchema,                // 表格数据结构
  colHeaders: CombatSkillTableConfig.showHeaderTexts,           // 列标题文本数组
  columns: [
    {
      data: 'headerOp',  // 操作列
      width: 120,
      renderer: buttonRenderer,
      readOnly: true
    },
    ...CombatSkillTableConfig.colDataMapping.slice(1)
  ],
  afterSelectionEnd: (row: number, column: number, _row2: number, _column2: number, _selectionData: any) => {
    handleCellSelection(row, column, CombatSkillTableConfig.name)
  }
})

// dmg_data表格配置
const dmgHotSettings = ref({
  ...HotSettingsTemplate,
  data: dmgTableData.value,
  colHeaders: DmgTableConfig.showHeaderTexts,
  columns: [
    {
      data: 'headerOp',  // 操作列
      width: 120,
      renderer: buttonRenderer,
      readOnly: true
    },
    ...DmgTableConfig.colDataMapping.slice(1)
  ],
  afterSelectionEnd: (row: number, column: number, _row2: number, _column2: number, _selectionData: any) => {
    handleCellSelection(row, column, DmgTableConfig.name)
  }
})

const buffHotSettings = ref({
  ...HotSettingsTemplate,
  data: buffTableData.value,
  colHeaders: BuffTableConfig.showHeaderTexts,
  columns: [
    {
      data: 'headerOp',  // 操作列
      width: 120,
      renderer: buttonRenderer,
      readOnly: true
    },
    ...BuffTableConfig.colDataMapping.slice(1)
  ],
  afterSelectionEnd: (row: number, column: number, _row2: number, _column2: number, _selectionData: any) => {
    handleCellSelection(row, column, BuffTableConfig.name)
  }
})

//  ---------------------------------------------- function define ---------------------------------------------

// 根据数据类型获取正确的ID字段
const getDataId = (data: CombatSkillTableData | DmgDataTableData | BuffTableData): number => {
  if (isCombatSkillTableData(data)) {
    return data.id
  } else if (isDmgDataTableData(data)) {
    return data.dmg_id
  } else {
    return data.buff_id
  }
}

const getTargetIp = (): string => {
  return targetIp.value === '开发服' ? '192.168.9.68:8127' : targetIp.value
}

const getTableData = (tab: typeof CombatSkillTableConfig.name | typeof DmgTableConfig.name | typeof BuffTableConfig.name):
  Ref<CombatSkillTableData[] | DmgDataTableData[] | BuffTableData[]> => {
  if (tab === CombatSkillTableConfig.name) {
    return combatSkillTableData
  } else if (tab === DmgTableConfig.name) {
    return dmgTableData
  } else {
    return buffTableData
  }
}

const getTableSetting = (tab: typeof CombatSkillTableConfig.name | typeof DmgTableConfig.name | typeof BuffTableConfig.name):
  Ref<any> => {
  if (tab === CombatSkillTableConfig.name) {
    return combatSkillHotSettings
  } else if (tab === DmgTableConfig.name) {
    return dmgHotSettings
  } else {
    return buffHotSettings
  }
}

const getHotInstance = (tab: typeof CombatSkillTableConfig.name | typeof DmgTableConfig.name | typeof BuffTableConfig.name):
  Ref<HotTableMethods | null> => {
  if (tab === CombatSkillTableConfig.name) {
    return combatSkillTableComponent
  } else if (tab === DmgTableConfig.name) {
    return dmgTableComponent
  } else {
    // todo - buff
    return ref(null)
  }
}

const getSearchId = (_nowActiveTab: typeof CombatSkillTableConfig.name | typeof DmgTableConfig.name | typeof BuffTableConfig.name): number | null => {
  return scriptId.value
}

const searchScript = () => {
  // window.aaaa = combatSkillTableComponent.value?.hotInstance
  const nowActiveTab = activeTab.value
  const hotInstance = getHotInstance(nowActiveTab)
  const updateTableData = getTableData(nowActiveTab)
  const searchId = getSearchId(nowActiveTab)
  console.log('searchScript', searchId)
  // 搜索的数据为空时， 搜索全部
  if (!searchId) {
    console.log('搜索全部')
    // 拼接url
    getAllDataCfg(http, getTargetIp(), nowActiveTab).then((res: any) => {
      console.log('获取所有技能成功:', res.data)
      // 空数据校验
      if (checkIsEmpty(res.data)) {
        ElMessage.info('无已修改的技能数据')
        return
      }
      updateTableData.value = res.data.map(convertToTableData)
      hotInstance.value?.hotInstance.updateData(updateTableData.value)
    }).catch((err: any) => {
      console.error('获取所有技能失败:', err)
      ElMessage.error('获取技能数据失败')
    })

  } else {
    console.log('搜索指定ID', searchId)
    getOneDataCfg(http, getTargetIp(), nowActiveTab, searchId).then((res: any) => {
      console.log('获取指定ID技能成功:', res.data)
      // 空数据校验
      if (checkIsEmpty(res.data)) {
        ElMessage.info('无已修改的技能数据')
        return
      }
      const convertedData = res.data.map(convertToTableData)
      // 基于id作为key更新TableData, 如果是没找到则新增
      convertedData.forEach((newData: CombatSkillTableData | DmgDataTableData | BuffTableData) => {
        const existingIndex = updateTableData.value.findIndex(item => {
          return getDataId(item) === getDataId(newData)
        });

        if (existingIndex >= 0) {
          // 如果找到匹配的ID则更新该条数据
          updateTableData.value[existingIndex] = newData;
        } else {
          // 如果没找到匹配的ID则添加为新数据
          (updateTableData.value as any[]).push(newData);
        }
      });
      hotInstance.value?.hotInstance.updateData(updateTableData.value)

    }).catch((err: any) => {
      console.error('获取指定ID技能失败:', err)
      ElMessage.error('获取技能数据失败')
    })
  }
}

// 处理提交技能数据
const handleSubmit = (row: number) => {
  const nowActiveTab = activeTab.value
  const tableData = getTableData(nowActiveTab)
  const rowData = tableData.value[row];
  if (!rowData) return;

  console.log('提交技能数据:', rowData);

  const dataId = getDataId(rowData)

  // 这里可以添加表单验证逻辑
  updateOneDataCfg(http, getTargetIp(), nowActiveTab, dataId, rowData).then((res: any) => {
    console.log('提交成功:', res);
    ElMessage.success('技能数据提交成功');
  }).catch((err: any) => {
    console.error('提交失败:', err);
    ElMessage.error('技能数据提交失败');
  });

};

// 处理删除技能数据
const handleDelete = (row: number) => {
  const nowActiveTab = activeTab.value
  const tableData = getTableData(nowActiveTab)
  const rowData = tableData.value[row];
  const hotInstance = getHotInstance(nowActiveTab)
  if (!rowData) return;

  console.log('删除技能数据行:', rowData);

  // 弹窗确认
  ElMessageBox.confirm('确定要删除此行数据吗?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    const id = getDataId(rowData)
    delOneDataCfg(http, getTargetIp(), nowActiveTab, id).then((res: any) => {
      console.log('删除成功:', res);
      // 从数据源中移除该行
      tableData.value.splice(row, 1);
      // 更新表格
      hotInstance.value?.hotInstance.updateData(tableData.value);
      ElMessage.success('删除成功');
    }).catch((err: any) => {
      console.error('删除失败:', err);
      ElMessage.error('删除失败');
    });

  })
};

// 处理单元格选择
const handleCellSelection = (row: number, column: number, tabName: typeof CombatSkillTableConfig.name | typeof DmgTableConfig.name) => {
  const hotInstance = getHotInstance(tabName).value?.hotInstance
  if (!hotInstance) return

  // 获取列配置信息
  const columnConfig = tabName === CombatSkillTableConfig.name
    ? combatSkillHotSettings.value.columns[column]
    : dmgHotSettings.value.columns[column]

  // 跳过操作列
  if (column === 0 || !columnConfig) {
    selectedCellData.value = null
    return
  }

  // 获取单元格属性名和数据
  const prop = columnConfig.data as string
  const tableData = getTableData(tabName).value
  if (!tableData || !tableData[row]) {
    selectedCellData.value = null
    return
  }

  // 存储单元格数据
  selectedCellData.value = (tableData[row] as any)[prop]
  selectedCellRow.value = row
  selectedCellCol.value = column
  selectedCellProp.value = prop

  // 获取列标题作为标签
  const columnHeaders = getTableSetting(tabName).value.colHeaders
  selectedCellLabel.value = columnHeaders[column]

  // 判断是否为数字类型
  isNumericCell.value = isNumericType(columnConfig)

  console.log('选中单元格:', {
    row,
    column,
    prop,
    value: selectedCellData.value,
    label: selectedCellLabel.value,
    isNumeric: isNumericCell.value
  })
}

// 将修改的单元格数据更新到表格
const updateCellToTable = () => {
  if (selectedCellData.value === null ||
    selectedCellRow.value === null ||
    selectedCellCol.value === null ||
    selectedCellProp.value === null) return

  const nowActiveTab = activeTab.value
  const tableData = getTableData(nowActiveTab)
  const hotInstance = getHotInstance(nowActiveTab)

  if (!tableData.value[selectedCellRow.value]) return

  // 更新表格数据
  (tableData.value[selectedCellRow.value] as any)[selectedCellProp.value] = selectedCellData.value

  // 刷新表格显示
  hotInstance.value?.hotInstance.updateData(tableData.value)

  ElMessage.success('单元格数据已更新')
}

// 检查是否为数字类型字段
const isNumericType = (column: any): boolean => {
  if (!column || !column.data) return false

  // 检查column配置中的type属性
  if (column.type === 'numeric') return true

  // 通过字段名判断
  const fieldName = column.data as string
  return fieldName === 'id' ||
    fieldName === 'dmg_id' ||
    fieldName === 'buff_id' ||
    fieldName.includes('_lev') ||
    fieldName.includes('_type') ||
    fieldName.includes('_num') ||
    fieldName.includes('_point')
}

// 处理页签切换
const handleTabClick = (tab: TabsPaneContext) => {
  console.log('切换到页签:', tab.props.name, '当前activeTab:', activeTab.value)

  // 清空选中单元格
  selectedCellData.value = null
  selectedCellRow.value = null
  selectedCellCol.value = null
  selectedCellProp.value = null

  // 等待 DOM 更新
  nextTick(() => {
    // 重新计算高度
    calculateTableHeight()

    // 根据页签类型渲染对应的表格
    if (activeTab.value === CombatSkillTableConfig.name && combatSkillTableComponent.value?.hotInstance) {
      console.log('渲染技能表格')
      combatSkillTableComponent.value.hotInstance.render()
    } else if (activeTab.value === DmgTableConfig.name && dmgTableComponent.value?.hotInstance) {
      console.log('渲染伤害表格')
      dmgTableComponent.value.hotInstance.render()
    }
  })
}

// 计算表格高度
const calculateTableHeight = () => {
  // 计算总的偏移量，考虑选中单元格展示区域的高度
  const totalOffset = selectedCellData.value ? 360 : 280

  // 设置表格高度
  tableHeight.value = window.innerHeight - totalOffset
}

// 监听选中单元格变化，调整表格高度
watch(selectedCellData, () => {
  calculateTableHeight()
})

// 监听目标IP变化，自动触发搜索
watch(targetIp, () => {
  // 如果是新输入的IP，自动加入targetLocation
  if (targetIp.value && !targetLocation.value.includes(targetIp.value)) {
    targetLocation.value.push(targetIp.value)
  }
  scriptId.value = undefined
  combatSkillTableData.value = []
  dmgTableData.value = []
  const tabsToUpdate = [CombatSkillTableConfig.name, DmgTableConfig.name] as const
  tabsToUpdate.forEach((tab) => {
    const hotInstance = getHotInstance(tab)
    const tableData = getTableData(tab)
    hotInstance.value?.hotInstance.updateData(tableData.value)
  })
  searchScript()
})

const checkIsEmpty = (data: any) => {
  if (!data || !Array.isArray(data) || data.length === 0 || (Array.isArray(data) && (data[0] == null || data[0] == undefined || data[0] == false))) {
    return true
  }
  return false
}

// 类型守卫函数
function isCombatSkillTableData(data: any): data is CombatSkillTableData {
  return data && 'id' in data;
}

function isDmgDataTableData(data: any): data is DmgDataTableData {
  return data && 'dmg_id' in data;
}

function isBuffTableData(data: any): data is BuffTableData {
  return data && 'buff_id' in data;
}

// ----------------------------------------------- function call -----------------------------------------------

onMounted(() => {
  // 加载保存的targetIp
  loadTargetState()

  // 设置事件监听和计算表格高度
  window.addEventListener('resize', calculateTableHeight)
  // 添加页面刷新前的保存事件
  window.addEventListener('beforeunload', saveTargetState)
  calculateTableHeight()
})

onUnmounted(() => {
  window.removeEventListener('resize', calculateTableHeight)
  window.removeEventListener('beforeunload', saveTargetState)
})

// 添加路由离开前的保存
onBeforeRouteLeave((_to, _from, next) => {
  saveTargetState()
  next()
})

const removeTargetLocation = (item: string) => {
  // 不能删除当前正在选中的
  if (targetIp.value === item) {
    ElMessage.warning('请先切换到其他IP再删除')
    return
  }
  const idx = targetLocation.value.indexOf(item)
  if (idx !== -1) {
    targetLocation.value.splice(idx, 1)
  }
}

</script>

<style scoped>
.table-container {
  margin-top: 20px;
  position: relative;
  min-height: 500px;
  overflow: hidden;
}

/* 选中单元格展示区域样式 */
.selected-cell-display {
  margin: 0 0 10px 0;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  padding: 5px;
  background-color: #f9f9f9;
}

.display-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 5px;
  padding: 0 10px;
  font-weight: bold;
}

.display-content {
  padding: 0 10px;
}

/* 主内容区域保持滚动条 */
:deep(.ht_master.handsontable .wtHolder) {
  overflow: auto !important;
}

/* 隐藏顶部列标题的滚动条 */
:deep(.ht_clone_top.handsontable .wtHolder) {
  overflow: hidden !important;
  overflow-x: hidden !important;
  overflow-y: hidden !important;
}

/* 隐藏左侧行号的滚动条 */
:deep(.ht_clone_left.handsontable .wtHolder) {
  overflow: hidden !important;
  overflow-x: hidden !important;
  overflow-y: hidden !important;
}

/* 隐藏左上角的滚动条 */
:deep(.ht_clone_top_left_corner.handsontable .wtHolder) {
  overflow: hidden !important;
  overflow-x: hidden !important;
  overflow-y: hidden !important;
}

:deep(.handsontable td) {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 4px 6px !important;
  position: relative;
}

:deep(.handsontable td[class*="current"]) {
  z-index: 2;
}

:deep(.handsontable td:not(:empty)) {
  z-index: 1;
}

:deep(.handsontable td:empty) {
  z-index: 0;
}

/* 移除其他可能影响的通用样式 */
:deep(.handsontable .wtHolder) {
  overflow: visible !important;
}

:deep(.handsontable .ht_clone_top) {
  z-index: 101;
}

:deep(.handsontable .ht_clone_left) {
  z-index: 102;
}

:deep(.handsontable .ht_clone_top_left_corner) {
  z-index: 103;
}

:deep(.handsontable ::-webkit-scrollbar) {
  width: 8px;
  height: 8px;
}

:deep(.handsontable ::-webkit-scrollbar-track) {
  background: #f1f1f1;
  border-radius: 4px;
}

:deep(.handsontable ::-webkit-scrollbar-thumb) {
  background: #888;
  border-radius: 4px;
}

:deep(.handsontable ::-webkit-scrollbar-thumb:hover) {
  background: #555;
}

/* 按钮样式 */
:deep(.el-button--small) {
  padding: 4px 8px;
  font-size: 12px;
  line-height: 1.2;
}
</style>
